#pragma once
//#include "stdafx.h"
#include "Grid.h"
#include "Space.h"
#include "BoundedSpace.h"
namespace org
{
	namespace spark
	{
		namespace data
		{
			//using org::spark::math::Function;
			//using org::spark::math::Matrix;
			using org::spark::space::BoundedSpace;
			using org::spark::space::Space;
			using org::spark::space::SpaceAgent;
			using org::spark::math::Vector;

			Grid::Grid(Space *space0, int xSize, int ySize)
			{
				InitializeInstanceFields();
				//assert(xSize > 0 && ySize > 0);
				//assert(space0 != 0);

				if (!(dynamic_cast<BoundedSpace*>(space0) != 0))
					////throw Error("Grid can be defined only for BoundedSpace");

				BoundedSpace *space = static_cast<BoundedSpace*>(space0);
				
				this->space = space;
				this->xSize = xSize;
				this->ySize = ySize;
				//space=dynamic_cast<org::spark::space::BoundedSpace*>(space);
				xStep =(org::spark::space::BoundedSpace*)space->getXSize() / xSize;
				yStep = (BoundedSpace*)space->getYSize() / ySize;
				invXStep = 1.0 / xStep;
				invYStep = 1.0 / yStep;

				this->wrapX =(BoundedSpace*) space->getWrapX();
				this->wrapY =(BoundedSpace*) space->getWrapY();
				this->xMin = (BoundedSpace*)space->getXMin();
				this->xMax =(BoundedSpace*) space->getXMax();
				this->yMin =(BoundedSpace*) space->getYMin();
				this->yMax = (BoundedSpace*)space->getYMax();


//ORIGINAL LINE: data = new double[xSize][ySize];
// NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
				data = org::RectangularArrays::ReturnRectangularDoubleArray(xSize, ySize);
				readData = data;
				writeData = data;
			}

			double **Grid::getData()
			{
				return data;
			}

			int Grid::getXSize()
			{
				return this->xSize;
			}

			int Grid::getYSize()
			{
				return this->ySize;
			}

			int Grid::restrictX(int x)
			{
				if (this->wrapX)
				{
					if (x < 0)
					{
						x += xSize;
						if (x < 0)
						{
							x += ((-x - 1) / xSize + 1) * this->xSize;
						}
					}
					else if (x >= this->xSize)
					{
						x = x - this->xSize;
						if (x >= this->xSize)
						{
							x -= (x / xSize) * this->xSize;
						}
					}

				}
				else
				{
					if (x < 0)
						x = 0;
					else if (x >= this->xSize)
						x = this->xSize - 1;
				}

				return x;
			}

			int Grid::restrictY(int y)
			{
				if (wrapY)
				{
					if (y < 0)
					{
						y += ySize;
						if (y < 0)
						{
							y += ((-y - 1) / ySize + 1) * ySize;
						}
					}
					else if (y >= ySize)
					{
						y = y - ySize;
						if (y >= ySize)
						{
							y -= (y / ySize) * ySize;
						}
					}

				}
				else
				{
					if (y < 0)
						y = 0;
					else if (y >= ySize)
						y = ySize - 1;
				}

				return y;
			}

			int Grid::findX(double x)
			{
				x -= xMin;
				x *= invXStep;

				int xx = static_cast<int>(floor(x));
				return restrictX(xx);
			}

			int Grid::findY(double y)
			{
				y -= yMin;
				y *= invYStep;

				int yy = static_cast<int>(floor(y));
				return restrictY(yy);
			}

			org::spark::math::Vector *Grid::getCenter(int x, int y)
			{
				return new Vector(x*xStep + xMin + xStep / 2, y*yStep + yMin + yStep / 2, 0);
			}

			double Grid::getXStep()
			{
				return xStep;
			}

			double Grid::getYStep()
			{
				return yStep;
			}

			double Grid::getValue(Vector *p)
			{
				return readData[findX(p->x)][findY(p->y)];
			}

			double Grid::addValue(Vector *p, double value)
			{
				int x = findX(p->x);
				int y = findY(p->y);

				writeData[x][y] += value;
				return readData[x][y];
			}

			void Grid::setValue(Vector *p, double value)
			{
				writeData[findX(p->x)][findY(p->y)] = value;
			}

			void Grid::setValue(double value)
			{
				for (int i = 0; i < xSize; i++)
					for (int j = 0; j < ySize; j++)
						writeData[i][j] = value;
			}

			org::spark::math::Vector *Grid::getSmoothGradient(Vector *p)
			{
				int x = findX(p->x);
				int y = findY(p->y);

				int x0 = restrictX(x - 1);
				int x1 = restrictX(x + 1);
				int y0 = restrictY(y - 1);
				int y1 = restrictY(y + 1);

				double dx = readData[x1][y] - readData[x0][y];
				double dy = readData[x][y1] - readData[x][y0];

				return new Vector(dx / (2 * xStep), dy / (2 * yStep), 0);
			}

			org::spark::math::Vector *Grid::getGradient(Vector *p)
			{
				int x = findX(p->x);
				int y = findY(p->y);

				double v = readData[x][y];
				int x1 = 0, y1 = 0;

				for (int i = -1; i <= 1; i++)
				{
					for (int j = -1; j <= 1; j++)
					{
						int xx = x + i;
						int yy = y + j;

						if (wrapX)
						{
							if (xx < 0)
								xx = xSize - 1;
							else if (xx >= xSize)
								xx = 0;
						}
						else
						{
							if (xx < 0)
								xx = 0;
							else if (xx >= xSize)
								xx = xSize - 1;
						}

						if (wrapY)
						{
							if (yy < 0)
								yy = ySize - 1;
							else if (yy >= ySize)
								yy = 0;
						}
						else
						{
							if (yy < 0)
								yy = 0;
							else if (yy >= ySize)
								yy = ySize - 1;
						}

						if (readData[xx][yy] > v)
						{
							x1 = i;
							y1 = j;
							v = readData[xx][yy];
						}
					}
				}

				double dv = v - readData[x][y];
				return new Vector(x1*dv, y1*dv, 0);
			}

			org::spark::math::Vector *Grid::getUphillDirection(Vector *p)
			{
				int x = findX(p->x);
				int y = findY(p->y);

				double v = readData[x][y];
				int x1 = 0, y1 = 0;

				for (int i = -1; i <= 1; i++)
				{
					for (int j = -1; j <= 1; j++)
					{
						int xx = x + i;
						int yy = y + j;

						if (wrapX)
						{
							if (xx < 0)
								xx = xSize - 1;
							else if (xx >= xSize)
								xx = 0;
						}
						else
						{
							if (xx < 0)
								xx = 0;
							else if (xx >= xSize)
								xx = xSize - 1;
						}

						if (wrapY)
						{
							if (yy < 0)
								yy = ySize - 1;
							else if (yy >= ySize)
								yy = 0;
						}
						else
						{
							if (yy < 0)
								yy = 0;
							else if (yy >= ySize)
								yy = ySize - 1;
						}

						if (readData[xx][yy] > v)
						{
							x1 = i;
							y1 = j;
							v = readData[xx][yy];
						}
					}
				}

				return new Vector(x1, y1, 0);
			}

			double Grid::addValue(SpaceAgent *agent, double value)
			{
				if (agent->getNode()->getSpace() == space)
					return addValue(agent->getPosition(), value);
				else
					return 0;
			}

			double Grid::getValue(SpaceAgent *agent)
			{
				if (agent->getNode()->getSpace() == space)
					return getValue(agent->getPosition());
				else
					return 0;
			}

			void Grid::setValue(SpaceAgent *agent, double value)
			{
				if (agent->getNode()->getSpace() == space)
					setValue(agent->getPosition(), value);
			}

			double Grid::getTotalNumber()
			{
				double v = 0;

				for (int i = 0; i < xSize; i++)
				{
//ORIGINAL LINE: double[] data = readData[i];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
					double *data = readData[i];
					for (int j = 0; j < ySize; j++)
						v += data[j];
				}

				return v;
			}

			/*void Grid::setValue(double f)
			{
				Vector *v = new Vector();
				v->x = xMin + xStep / 2;

				for (int i = 0; i < xSize; i++, v->x += xStep)
				{
					v->y = yMin + yStep / 2;

					for (int j = 0; j < ySize; j++, v->y += yStep)
					{
						writeData[i][j] = f;
					}
				}
			}*/

			void Grid::multiply(double value)
			{
				for (int i = 0; i < xSize; i++)
				{
//ORIGINAL LINE: double[] data = writeData[i];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
					double *data = writeData[i];
					for (int j = 0; j < ySize; j++)
						data[j] *= value;
				}
			}

			void Grid::add(double value)
			{
				for (int i = 0; i < xSize; i++)
				{
//ORIGINAL LINE: double[] data = writeData[i];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
					double *data = writeData[i];
					for (int j = 0; j < ySize; j++)
						data[j] += value;
				}
			}

			/*void Grid::convolution(Matrix *m)
			{
				int rows = m->getRowsNumber();
				int cols = m->getColsNumber();
				if ((rows & 1) == 0 || (cols & 1) == 0)
					//throw Error("The matrix should be of odd order");
				int r2 = rows / 2;
				int c2 = cols / 2;
//ORIGINAL LINE: double[][] mData = m.getData();
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **mData = m->getData();

				if (dataCopy == 0)
//ORIGINAL LINE: dataCopy = new double[xSize][ySize];
// NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
					dataCopy = RectangularArrays::ReturnRectangularDoubleArray(xSize, ySize);
				else
				{
					for (int i = 0; i < xSize; i++)
						for (int j = 0; j < ySize; j++)
							dataCopy[i][j] = 0;
				}

				for (int j = 0; j < ySize; j++)
					for (int i = 0; i < xSize; i++)
					{
						double v = 0;
						for (int jj = -c2, jm = 0; jj <= c2; jj++, jm++)
							for (int ii = -r2, im = 0; ii <= r2; ii++, im++)
							{
								int x = i + ii;
								int y = j + jj;

								if (x < 0)
									x += xSize;
								else if (x >= xSize)
									x -= xSize;

								if (y < 0)
									y += ySize;
								else if (y >= ySize)
									y -= ySize;

								v += mData[im][jm] * readData[x][y];
							}

						dataCopy[i][j] = v;
					}

//ORIGINAL LINE: double[][] temp = data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **temp = data;
				data = dataCopy;
				readData = writeData = data;
				dataCopy = temp;
			}*/

			/*void Grid::diffuse2(double p)
			{
				double q = p / 8;
				diffusion->set(0, 0, q);
				diffusion->set(1, 0, q);
				diffusion->set(2, 0, q);
				diffusion->set(0, 1, q);
				diffusion->set(2, 1, q);
				diffusion->set(0, 2, q);
				diffusion->set(1, 2, q);
				diffusion->set(2, 2, q);
				diffusion->set(1, 1, 1 - p);

				convolution(diffusion);
			}*/

			void Grid::diffuse(double p, Grid *mask)
			{
				if (mask->xSize != xSize || mask->ySize != ySize)
					return;

				if (dataCopy == 0)
//ORIGINAL LINE: dataCopy = new double[xSize][ySize];
// NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
					dataCopy = RectangularArrays::ReturnRectangularDoubleArray(xSize, ySize);

//ORIGINAL LINE: double[][] maskData = mask.getData();
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **maskData = mask->getData();
				double q = p / 8;

				for (int x = 0; x < xSize; x++)
				{
					for (int y = 0; y < ySize; y++)
					{
						if (maskData[x][y] > 0.0)
						{
							// No diffusion
							dataCopy[x][y] = 0.0;
							continue;
						}

						// n is the number of good neighbors
						int n = 0;
						double v = 0;

						for (int i = -1; i <= 1; i++)
						{
							for (int j = -1; j <= 1; j++)
							{
								int x1 = x + i;
								int y1 = y + j;

								// Bound x1
								if (x1 < 0)
								{
									if (wrapX)
										x1 = xSize - 1;
									else
										continue;
								}
								else if (x1 == xSize)
								{
									if (wrapX)
										x1 = 0;
									else
										continue;
								}

								// Bound y1
								if (y1 < 0)
								{
									if (wrapY)
										y1 = ySize - 1;
									else
										continue;
								}
								else if (y1 == ySize)
								{
									if (wrapY)
										y1 = 0;
									else
										continue;
								}

								if (maskData[x1][y1] > 0.0)
									continue;

								n++;
								v += data[x1][y1];
							} // j
						} // i

						double pp = 1 - n * q;
						dataCopy[x][y] = data[x][y] * pp + v * q;
					} // y
				} // x

//ORIGINAL LINE: double[][] temp = data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **temp = data;
				data = dataCopy;
				readData = writeData = data;
				dataCopy = temp;
			}

			void Grid::diffuse(double p)
			{
				if (dataCopy == 0)
//ORIGINAL LINE: dataCopy = new double[xSize][ySize];
// NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
					dataCopy = RectangularArrays::ReturnRectangularDoubleArray(xSize, ySize);
						/*		else {
									// Fill it with zeros
									for (int i = 0; i < xSize; i++) {
										double[] tmp = dataCopy[i];
										for (int j = 0; j < ySize; j++)
											tmp[j] = 0;
									}
								}
						*/		
				if (wrapX)
				{
					if (wrapY)
						diffuseTT(p);
						//				old_diffusion(p);
					else
						diffuseTF(p);
				}
				else
				{
					if (wrapY)
						diffuseFT(p);
					else
						diffuseFF(p);
				}
			}

			void Grid::diffuseFF(double const p)
			{
				const int xSize2 = xSize - 1;
				const int ySize2 = ySize - 1;
				const double p2 = 1 - p;
				const double q = p / 8.0;

				// TODO: it is assumed that xSize >= 2 and ySize >= 2

				// Diffusion for corners
				// (0,0)
				double pp = p2 + 5 * q;
				dataCopy[0][0] = data[0][0] * pp + q * (data[1][0] + data[0][1] + data[1][1]);

				// (xSize2,0)
				dataCopy[xSize2][0] = data[xSize2][0] * pp + q * (data[xSize2 - 1][0] + data[xSize2 - 1][1] + data[xSize2][1]);

				// (xSize2,ySize2)
				dataCopy[xSize2][ySize2] = data[xSize2][ySize2] * pp + q * (data[xSize2 - 1][ySize2] + data[xSize2 - 1][ySize2 - 1] + data[xSize2][ySize2 - 1]);

				// (0,ySize2)
				dataCopy[0][ySize2] = data[0][ySize2] * pp + q * (data[1][ySize2] + data[1][ySize2 - 1] + data[0][ySize2 - 1]);


				// Diffusion for borders
				// Left, x = 0
				pp = p2 + 3 * q;

//ORIGINAL LINE: double[] data1 = data[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data1 = data[0];
//ORIGINAL LINE: double[] data2 = data[1];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data2 = data[1];
//ORIGINAL LINE: double[] r = dataCopy[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *r = dataCopy[0];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = data1[y] * pp + q * (data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Right, x = xSize2
				data1 = data[xSize2];
				data2 = data[xSize2 - 1];
				r = dataCopy[xSize2];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = data1[y] * pp + q * (data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Bottom, y = 0
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][0] = data[x][0] * pp + q * (data[x - 1][0] + data[x + 1][0] + data[x - 1][1] + data[x][1] + data[x + 1][1]);
				}

				// Top, y = ySize2
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][ySize2] = data[x][ySize2] * pp + q * (data[x - 1][ySize2] + data[x + 1][ySize2] + data[x - 1][ySize2 - 1] + data[x][ySize2 - 1] + data[x + 1][ySize2 - 1]);
				}


				// Diffusion for the center
				for (int x = 1; x < xSize2; x++)
				{
//ORIGINAL LINE: double[] data0 = data[x - 1];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
					double *data0 = data[x - 1];
					data1 = data[x];
					data2 = data[x + 1];
					r = dataCopy[x];

					for (int y = 1; y < ySize2; y++)
					{
						r[y] = data1[y] * p2 + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
					}
				}

//ORIGINAL LINE: double[][] temp = data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **temp = data;
				data = dataCopy;
				// TODO: is it correct?
				readData = writeData = data;
				dataCopy = temp;
			}

			void Grid::diffuseFT(double const p)
			{
				const int xSize2 = xSize - 1;
				const int ySize2 = ySize - 1;
				const double p2 = 1 - p;
				const double q = p / 8.0;

				// TODO: it is assumed that xSize >= 2 and ySize >= 2

				// Diffusion for corners
				// (0,0)
				double pp = p2 + 3 * q;
				dataCopy[0][0] = data[0][0] * pp + q * (data[1][0] + data[0][1] + data[1][1] + data[0][ySize2] + data[1][ySize2]);

				// (xSize2,0)
				dataCopy[xSize2][0] = data[xSize2][0] * pp + q * (data[xSize2 - 1][0] + data[xSize2 - 1][1] + data[xSize2][1] + data[xSize2 - 1][ySize2] + data[xSize2][ySize2]);

				// (xSize2,ySize2)
				dataCopy[xSize2][ySize2] = data[xSize2][ySize2] * pp + q * (data[xSize2 - 1][ySize2] + data[xSize2 - 1][ySize2 - 1] + data[xSize2][ySize2 - 1] + data[xSize2 - 1][0] + data[xSize2][0]);

				// (0,ySize2)
				dataCopy[0][ySize2] = data[0][ySize2] * pp + q * (data[1][ySize2] + data[1][ySize2 - 1] + data[0][ySize2 - 1] + data[0][0] + data[1][0]);


				// Diffusion for borders
				// Left, x = 0
				pp = p2 + 3 * q;

//ORIGINAL LINE: double[] data1 = data[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data1 = data[0];
//ORIGINAL LINE: double[] data2 = data[1];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data2 = data[1];
//ORIGINAL LINE: double[] r = dataCopy[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *r = dataCopy[0];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = data1[y] * pp + q * (data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Right, x = xSize2
				data1 = data[xSize2];
				data2 = data[xSize2 - 1];
				r = dataCopy[xSize2];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = data1[y] * pp + q * (data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Bottom, y = 0
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][0] = data[x][0] * p2 + q * (data[x - 1][0] + data[x + 1][0] + data[x - 1][1] + data[x][1] + data[x + 1][1] + data[x - 1][ySize2] + data[x][ySize2] + data[x + 1][ySize2]);
				}

				// Top, y = ySize2
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][ySize2] = data[x][ySize2] * p2 + q * (data[x - 1][ySize2] + data[x + 1][ySize2] + data[x - 1][ySize2 - 1] + data[x][ySize2 - 1] + data[x + 1][ySize2 - 1] + data[x - 1][0] + data[x][0] + data[x + 1][0]);
				}


				// Diffusion for the center
				for (int x = 1; x < xSize2; x++)
				{
//ORIGINAL LINE: double[] data0 = data[x - 1];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
					double *data0 = data[x - 1];
					data1 = data[x];
					data2 = data[x + 1];
					r = dataCopy[x];

					for (int y = 1; y < ySize2; y++)
					{
						r[y] = data1[y] * p2 + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
					}
				}

//ORIGINAL LINE: double[][] temp = data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **temp = data;
				data = dataCopy;
				// TODO: is it correct?
				readData = writeData = data;
				dataCopy = temp;
			}

			void Grid::diffuseTF(double const p)
			{
				const int xSize2 = xSize - 1;
				const int ySize2 = ySize - 1;
				const double p2 = 1 - p;
				const double q = p / 8.0;

				// TODO: it is assumed that xSize >= 2 and ySize >= 2

				// Diffusion for corners
				// (0,0)
				double pp = p2 + 3 * q;
				dataCopy[0][0] = data[0][0] * pp + q * (data[1][0] + data[0][1] + data[1][1] + data[xSize2][0] + data[xSize2][1]);

				// (xSize2,0)
				dataCopy[xSize2][0] = data[xSize2][0] * pp + q * (data[xSize2 - 1][0] + data[xSize2 - 1][1] + data[xSize2][1] + data[0][0] + data[0][1]);

				// (xSize2,ySize2)
				dataCopy[xSize2][ySize2] = data[xSize2][ySize2] * pp + q * (data[xSize2 - 1][ySize2] + data[xSize2 - 1][ySize2 - 1] + data[xSize2][ySize2 - 1] + data[0][ySize2 - 1] + data[0][ySize2]);

				// (0,ySize2)
				dataCopy[0][ySize2] = data[0][ySize2] * pp + q * (data[1][ySize2] + data[1][ySize2 - 1] + data[0][ySize2 - 1] + data[xSize2][ySize2 - 1] + data[xSize2][ySize2]);


				// Diffusion for borders
				// Left, x = 0
				pp = p2 + 3 * q;

//ORIGINAL LINE: double[] data0 = data[xSize2];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data0 = data[xSize2];
//ORIGINAL LINE: double[] data1 = data[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data1 = data[0];
//ORIGINAL LINE: double[] data2 = data[1];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data2 = data[1];
//ORIGINAL LINE: double[] r = dataCopy[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *r = dataCopy[0];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = data1[y] * p2 + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Right, x = xSize2
				data0 = data[xSize2 - 1];
				data1 = data[xSize2];
				data2 = data[0];
				r = dataCopy[xSize2];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = data1[y] * p2 + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Bottom, y = 0
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][0] = data[x][0] * pp + q * (data[x - 1][0] + data[x + 1][0] + data[x - 1][1] + data[x][1] + data[x + 1][1]);
				}

				// Top, y = ySize2
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][ySize2] = data[x][ySize2] * pp + q * (data[x - 1][ySize2] + data[x + 1][ySize2] + data[x - 1][ySize2 - 1] + data[x][ySize2 - 1] + data[x + 1][ySize2 - 1]);
				}


				// Diffusion for the center
				for (int x = 1; x < xSize2; x++)
				{
					data0 = data[x - 1];
					data1 = data[x];
					data2 = data[x + 1];
					r = dataCopy[x];

					for (int y = 1; y < ySize2; y++)
					{
						r[y] = data1[y] * p2 + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
					}
				}

//ORIGINAL LINE: double[][] temp = data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **temp = data;
				data = dataCopy;
				// TODO: is it correct?
				readData = writeData = data;
				dataCopy = temp;
			}

			void Grid::diffuseTT(double const p)
			{
				const int xSize2 = xSize - 1;
				const int ySize2 = ySize - 1;
				const double p2 = 1 - p;
				const double q = p / 8.0;

				// TODO: it is assumed that xSize >= 2 and ySize >= 2

				// Diffusion for corners
				// (0,0)
				dataCopy[0][0] = p2 * data[0][0] + q * (data[1][0] + data[1][1] + data[0][1] + data[xSize2][1] + data[xSize2][0] + data[xSize2][ySize2] + data[0][ySize2] + data[1][ySize2]);

				// (xSize2,0)
				dataCopy[xSize2][0] = p2 * data[xSize2][0] + q * (data[0][0] + data[0][1] + data[xSize2][1] + data[xSize2 - 1][1] + data[xSize2 - 1][0] + data[xSize2 - 1][ySize2] + data[xSize2][ySize2] + data[0][ySize2]);

				// (0,ySize2)
				dataCopy[0][ySize2] = p2 * data[0][ySize2] + q * (data[1][ySize2] + data[1][0] + data[0][0] + data[xSize2][0] + data[xSize2][ySize2] + data[xSize2][ySize2 - 1] + data[0][ySize2 - 1] + data[1][ySize2 - 1]);

				// (xSize2,ySize2)
				dataCopy[xSize2][ySize2] = p2 * data[xSize2][ySize2] + q * (data[0][ySize2] + data[0][0] + data[xSize2][0] + data[xSize2 - 1][0] + data[xSize2 - 1][ySize2] + data[xSize2 - 1][ySize2 - 1] + data[xSize2][ySize2 - 1] + data[0][ySize2 - 1]);

				// Diffusion for borders
				// Left, x = 0

//ORIGINAL LINE: double[] data0 = data[xSize2];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data0 = data[xSize2];
//ORIGINAL LINE: double[] data1 = data[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data1 = data[0];
//ORIGINAL LINE: double[] data2 = data[1];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *data2 = data[1];
//ORIGINAL LINE: double[] r = dataCopy[0];
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double *r = dataCopy[0];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = p2 * data1[y] + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Right, x = xSize2
				data0 = data[xSize2 - 1];
				data1 = data[xSize2];
				data2 = data[0];
				r = dataCopy[xSize2];
				for (int y = 1; y < ySize2; y++)
				{
					r[y] = p2 * data1[y] + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
				}

				// Bottom, y = 0
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][0] = p2 * data[x][0] + q * (data[x - 1][ySize2] + data[x - 1][0] + data[x - 1][1] + data[x][ySize2] + data[x][1] + data[x + 1][ySize2] + data[x + 1][0] + data[x + 1][1]);
				}

				// Top, y = ySize2
				for (int x = 1; x < xSize2; x++)
				{
					dataCopy[x][ySize2] = p2 * data[x][ySize2] + q * (data[x - 1][ySize2 - 1] + data[x - 1][ySize2] + data[x - 1][0] + data[x][ySize2 - 1] + data[x][0] + data[x + 1][ySize2 - 1] + data[x + 1][ySize2] + data[x + 1][0]);
				}


				// Diffusion for the center
				for (int x = 1; x < xSize2; x++)
				{
					data0 = data[x - 1];
					data1 = data[x];
					data2 = data[x + 1];
					r = dataCopy[x];

					for (int y = 1; y < ySize2; y++)
					{
						r[y] = p2 * data1[y] + q * (data0[y - 1] + data0[y] + data0[y + 1] + data1[y - 1] + data1[y + 1] + data2[y - 1] + data2[y] + data2[y + 1]);
					}
				}

//ORIGINAL LINE: double[][] temp = data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **temp = data;
				data = dataCopy;
				// TODO: is it correct?
				readData = writeData = data;
				dataCopy = temp;
			}

			void Grid::old_diffusion(double p)
			{
				double q = p / 8.0;

				for (int x = 0; x < xSize; x++)
				{
					for (int y = 0; y < ySize; y++)
					{
						double v = data[x][y] * (1 - p);
						//				dataCopy[x][y] += data[x][y] * (1 - p);

						for (int i = -1; i <= 1; i++)
							for (int j = -1; j <= 1; j++)
							{
								if (i == 0 && j == 0)
									continue;

								int xx = x + i;
								int yy = y + j;

								if (xx < 0)
									xx = xSize - 1;
								else if (xx >= xSize)
									xx = 0;

								if (yy < 0)
									yy = ySize - 1;
								else if (yy >= ySize)
									yy = 0;

						//						dataCopy[xx][yy] += data[x][y] * q;
								v += data[xx][yy] * q;
							}

						dataCopy[x][y] = v;
					}
				}

//ORIGINAL LINE: double[][] temp = data;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
				double **temp = data;
				data = dataCopy;
				// TODO: is it correct?
				readData = writeData = data;
				dataCopy = temp;
			}

			double Grid::getTotalNumber(double xMin, double xMax, double yMin, double yMax)
			{
				int x0 = findX(xMin);
				int y0 = findY(yMin);
				int x1 = findX(xMax);
				int y1 = findY(yMax);

				double val = 0;

				for (int i = x0; i <= x1; i++)
					for (int j = y0; j <= y1; j++)
						val += readData[i][j];

				return val;
			}

			double Grid::getTotalNumber(DataLayer *filter, double val)
			{
				double v = 0;

				// TODO: other cases
				if (dynamic_cast<Grid*>(filter) != 0)
				{
					Grid *filterGrid = static_cast<Grid*>(filter);

					// TODO: xMin, step are also important
					if (filterGrid->xSize == this->xSize && filterGrid->ySize == this->ySize)
					{
//ORIGINAL LINE: double[][] filterData = filterGrid.readData;
// WARNING: Since the array size is not known in this declaration, converted this array to a pointer.   call 'delete[]' where appropriate:
						double **filterData = filterGrid->readData;

						for (int i = 0; i < xSize; i++)
							for (int j = 0; j < ySize; j++)
							{
								if (filterData[i][j] == val)
									v += readData[i][j];
							}
					}
				}

				return v;
			}

			void Grid::process(long long tick)
			{
			}

			double Grid::getValue(int x, int y)
			{
				return readData[x][y];
			}

			void Grid::setValue(int x, int y, double value)
			{
				writeData[x][y] = value;
			}

			void Grid::addValue(int x, int y, double value)
			{
				writeData[x][y] += value;
			}

			double Grid::getMax()
			{
				double max = readData[0][0];

				for (int i = 0; i < xSize; i++)
					for (int j = 0; j < ySize; j++)
					{
						if (readData[i][j] > max)
							max = readData[i][j];
					}

				return max;
			}

			double Grid::getMin()
			{
				double min = readData[0][0];

				for (int i = 0; i < xSize; i++)
					for (int j = 0; j < ySize; j++)
					{
						if (readData[i][j] < min)
							min = readData[i][j];
					}

				return min;
			}

			org::spark::space::Space *Grid::getSpace()
			{
				return space;
			}

			void Grid::setSpace(Space *space)
			{
				this->space = space;
			}

			/*void Grid::readObject(ObjectInputStream *ois) //throw(IOException, ClassNotFoundException)
			{

				ois->defaultReadObject();
			}

			void Grid::writeObject(ObjectOutputStream *oos) //throw(IOException)
			{
				oos->defaultWriteObject();
			}*/

			void Grid::beginStep()
			{
			}

			void Grid::endStep()
			{
			}

			void Grid::InitializeInstanceFields()
			{
				//diffusion = new org::spark::math::Matrix(3, 3);
			}
		}
	}
}
